"""
SQL语法分析器
使用PLY库实现SQL语句的语法分析，构建抽象语法树(AST)
"""

import ply.yacc as yacc
from .lexer import SQLLexer

class SQLParser:
    """SQL语法分析器"""
    
    def __init__(self):
        """初始化语法分析器"""
        self.lexer = SQLLexer()
        self.tokens = self.lexer.tokens
        self.parser = yacc.yacc(module=self)
    
    # 语法规则定义
    def p_statement(self, p):
        """statement : create_statement
                     | insert_statement
                     | select_statement
                     | update_statement
                     | delete_statement
                     | drop_statement
                     | login_statement
                     | logout_statement
                     | create_user_statement
                     | grant_statement
                     | revoke_statement
                     | show_grants_statement
                     | show_users_statement
                     | change_password_statement"""
        p[0] = p[1]
    
    # CREATE TABLE语句
    def p_create_statement(self, p):
        """create_statement : CREATE TABLE IDENTIFIER LPAREN column_list RPAREN"""
        p[0] = {
            'type': 'CREATE_TABLE',
            'table_name': p[3],
            'columns': p[5]
        }
    
    def p_column_list(self, p):
        """column_list : column_list COMMA column_def
                       | column_def"""
        if len(p) == 4:
            p[0] = p[1] + [p[3]]
        else:
            p[0] = [p[1]]
    
    def p_column_def(self, p):
        """column_def : IDENTIFIER data_type
                      | IDENTIFIER data_type PRIMARY KEY"""
        column_def = {
            'name': p[1],
            'type': p[2]
        }
        if len(p) == 5:  # 有PRIMARY KEY
            column_def['primary_key'] = True
        p[0] = column_def
    
    def p_data_type(self, p):
        """data_type : INT
                     | VARCHAR LPAREN NUMBER RPAREN
                     | FLOAT
                     | BOOLEAN"""
        if len(p) == 2:
            p[0] = {'type': p[1].lower()}
        else:  # VARCHAR(n)
            p[0] = {'type': 'varchar', 'length': p[3]}
    
    # INSERT语句
    def p_insert_statement(self, p):
        """insert_statement : INSERT INTO IDENTIFIER VALUES LPAREN value_list RPAREN"""
        p[0] = {
            'type': 'INSERT',
            'table_name': p[3],
            'values': p[6]
        }
    
    def p_value_list(self, p):
        """value_list : value_list COMMA value
                      | value"""
        if len(p) == 4:
            p[0] = p[1] + [p[3]]
        else:
            p[0] = [p[1]]
    
    def p_value(self, p):
        """value : NUMBER
                 | STRING
                 | NULL"""
        p[0] = p[1]
    
    # SELECT语句
    def p_select_statement(self, p):
        """select_statement : SELECT select_list FROM IDENTIFIER where_clause"""
        where_clause = None
        if len(p) > 5 and p[5] is not None:
            where_clause = p[5]
        p[0] = {
            'type': 'SELECT',
            'columns': p[2],
            'table_name': p[4],
            'where': where_clause
        }
    
    def p_select_list(self, p):
        """select_list : select_list COMMA column_reference
                       | column_reference
                       | TIMES"""
        if len(p) == 2:
            if p[1] == '*':
                p[0] = '*'
            else:
                p[0] = [p[1]]
        elif len(p) == 4:
            p[0] = p[1] + [p[3]]
        else:
            p[0] = [p[1]]
    
    def p_column_reference(self, p):
        """column_reference : IDENTIFIER
                            | IDENTIFIER DOT IDENTIFIER"""
        if len(p) == 2:
            p[0] = p[1]
        else:
            p[0] = f"{p[1]}.{p[3]}"
    
    def p_where_clause(self, p):
        """where_clause : WHERE condition
                        | empty"""
        if len(p) > 2:
            p[0] = p[2]
        else:
            p[0] = None
    
    def p_condition(self, p):
        """condition : condition AND condition
                     | condition OR condition
                     | NOT condition
                     | expression comparison_op expression
                     | LPAREN condition RPAREN"""
        if len(p) == 4:
            if p[1] == '(':
                p[0] = p[2]
            else:
                p[0] = {
                    'type': p[2],
                    'left': p[1],
                    'right': p[3]
                }
        elif len(p) == 3:
            p[0] = {
                'type': p[1],
                'operand': p[2]
            }
        else:
            p[0] = {
                'type': p[2],
                'left': p[1],
                'right': p[3]
            }
    
    def p_comparison_op(self, p):
        """comparison_op : EQ
                         | NE
                         | LT
                         | LE
                         | GT
                         | GE"""
        p[0] = p[1]
    
    def p_expression(self, p):
        """expression : expression PLUS expression
                      | expression MINUS expression
                      | expression TIMES expression
                      | expression DIVIDE expression
                      | column_reference
                      | value
                      | LPAREN expression RPAREN"""
        if len(p) == 4:
            if p[1] == '(':
                p[0] = p[2]
            else:
                p[0] = {
                    'type': 'binary_op',
                    'operator': p[2],
                    'left': p[1],
                    'right': p[3]
                }
        else:
            p[0] = p[1]
    
    # UPDATE语句
    def p_update_statement(self, p):
        """update_statement : UPDATE IDENTIFIER SET assignment_list where_clause"""
        p[0] = {
            'type': 'UPDATE',
            'table_name': p[2],
            'assignments': p[4],
            'where': p[5]
        }
    
    def p_assignment_list(self, p):
        """assignment_list : assignment_list COMMA assignment
                           | assignment"""
        if len(p) == 4:
            p[0] = p[1] + [p[3]]
        else:
            p[0] = [p[1]]
    
    def p_assignment(self, p):
        """assignment : IDENTIFIER EQ value"""
        p[0] = {
            'column': p[1],
            'value': p[3]
        }
    
    # DELETE语句
    def p_delete_statement(self, p):
        """delete_statement : DELETE FROM IDENTIFIER where_clause"""
        p[0] = {
            'type': 'DELETE',
            'table_name': p[3],
            'where': p[4]
        }
    
    # DROP语句
    def p_drop_statement(self, p):
        """drop_statement : DROP TABLE IDENTIFIER"""
        p[0] = {
            'type': 'DROP_TABLE',
            'table_name': p[3]
        }
    
    # 登录语句
    def p_login_statement(self, p):
        """login_statement : LOGIN IDENTIFIER STRING"""
        p[0] = {
            'type': 'LOGIN',
            'username': p[2],
            'password': p[3]
        }
    
    # 登出语句
    def p_logout_statement(self, p):
        """logout_statement : LOGOUT"""
        p[0] = {
            'type': 'LOGOUT'
        }
    
    # 创建用户语句
    def p_create_user_statement(self, p):
        """create_user_statement : CREATE USER IDENTIFIER STRING ROLE IDENTIFIER"""
        p[0] = {
            'type': 'CREATE_USER',
            'username': p[3],
            'password': p[4],
            'role': p[6]
        }
    
    # 授权语句
    def p_grant_statement(self, p):
        """grant_statement : GRANT permission_list ON IDENTIFIER TO IDENTIFIER"""
        p[0] = {
            'type': 'GRANT',
            'permissions': p[2],
            'table_name': p[4],
            'username': p[6]
        }
    
    # 撤销权限语句
    def p_revoke_statement(self, p):
        """revoke_statement : REVOKE permission_list ON IDENTIFIER FROM IDENTIFIER"""
        p[0] = {
            'type': 'REVOKE',
            'permissions': p[2],
            'table_name': p[4],
            'username': p[6]
        }
    
    # 显示权限语句
    def p_show_grants_statement(self, p):
        """show_grants_statement : SHOW GRANTS FOR IDENTIFIER"""
        p[0] = {
            'type': 'SHOW_GRANTS',
            'username': p[4]
        }
    
    # 显示用户语句
    def p_show_users_statement(self, p):
        """show_users_statement : SHOW USERS"""
        p[0] = {
            'type': 'SHOW_USERS'
        }
    
    # 修改密码语句
    def p_change_password_statement(self, p):
        """change_password_statement : CHANGE PASSWORD STRING TO STRING"""
        p[0] = {
            'type': 'CHANGE_PASSWORD',
            'old_password': p[3],
            'new_password': p[5]
        }
    
    # 权限列表
    def p_permission_list(self, p):
        """permission_list : permission_list COMMA IDENTIFIER
                           | IDENTIFIER"""
        if len(p) == 4:
            p[0] = p[1] + [p[3]]
        else:
            p[0] = [p[1]]
    
    # 空产生式
    def p_empty(self, p):
        """empty :"""
        pass
    
    # 错误处理
    def p_error(self, p):
        if p:
            print(f"语法错误: 在 '{p.value}' 附近，位置 {p.lexpos}")
            print(f"当前状态: {p}")
        else:
            print("语法错误: 意外的文件结束")
    
    def parse(self, text):
        """解析SQL语句"""
        try:
            result = self.parser.parse(text, lexer=self.lexer.lexer)
            return result
        except Exception as e:
            print(f"解析错误: {str(e)}")
            return None
    
    def test(self, text):
        """测试语法分析器"""
        print(f"输入: {text}")
        ast = self.parse(text)
        if ast:
            print("AST:")
            self.print_ast(ast, 0)
        else:
            print("解析失败")
        return ast
    
    def print_ast(self, node, indent):
        """打印AST"""
        if isinstance(node, dict):
            for key, value in node.items():
                if isinstance(value, (dict, list)):
                    print("  " * indent + f"{key}:")
                    if isinstance(value, list):
                        for i, item in enumerate(value):
                            print("  " * (indent + 1) + f"[{i}]:")
                            self.print_ast(item, indent + 2)
                    else:
                        self.print_ast(value, indent + 1)
                else:
                    print("  " * indent + f"{key}: {value}")
        else:
            print("  " * indent + str(node))

# 测试函数
if __name__ == "__main__":
    parser = SQLParser()
    
    # 测试用例
    test_cases = [
        "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50))",
        "INSERT INTO users VALUES (1, 'Alice')",
        "SELECT * FROM users WHERE age > 20",
        "UPDATE users SET age = 25 WHERE id = 1",
        "DELETE FROM users WHERE age < 18",
        "DROP TABLE users"
    ]
    
    for test_case in test_cases:
        print("\n" + "="*50)
        parser.test(test_case)
